#include "CmdReceiver.h"
#include "CommandData.h"
#include "CommandHandler.h"
#include <wx/wx.h>
#include <wx/thread.h>
#include <wx/socket.h>
#include <wx/stream.h>
#include <wx/sckstrm.h>
#include <wx/txtstrm.h>
#include <list>
#include <map>

using namespace std;

static CommandReceiver* instance = NULL;
static wxMutex instanceLock;

class HandlerImpl : public wxThread, public CommandReceiver
{
public:
	HandlerImpl();

	void AttachCommandHandler(CommandHandler* cmdHandler);
	void DetachCommandHandler(CommandHandler* cmdHandler);

	ExitCode Entry();
private:
	wxSocketServer* server;
	wxSocketBase* client;
	wxSocketInputStream* sockIn;
	wxSocketOutputStream* sockOut;
	wxTextInputStream* textIn;
	wxTextOutputStream* textOut;

	list<CommandHandler*> handlers;
};

HandlerImpl::HandlerImpl() 
{
	client = NULL;
	wxIPV4address addr;
	addr.Hostname(_T("127.0.0.1"));
	addr.Service(CAPY_TEST_CMD_PORT);
	server = new wxSocketServer(addr);
}


wxThread::ExitCode HandlerImpl::Entry() 
{
	list<CommandHandler*>::iterator iter, end;

	while (true)
	{
		if (client == NULL)
		{
			client = server->Accept();
			client->SetTimeout(CAPY_CMD_TIMEOUT_SEC);

			sockIn = new wxSocketInputStream(*client);
			textIn = new wxTextInputStream(*sockIn);
			sockOut = new wxSocketOutputStream(*client);
			textOut = new wxTextOutputStream(*sockOut);
		} 
		else 
		{
			CommandData cmdData(
				textIn->ReadWord(),
				textIn->ReadWord(),
				textIn->ReadLine()
				);

			iter = handlers.begin();
			end = handlers.end();
		
			for (; iter != end; iter++)
			{
				textOut->WriteString((*iter)->HandleCommand(cmdData));
			}
		}
	}
	return NULL;
}


void HandlerImpl::AttachCommandHandler(CommandHandler* cmdHandler)
{
	handlers.push_back(cmdHandler);
}

void HandlerImpl::DetachCommandHandler(CommandHandler* cmdHandler)
{
	handlers.remove(cmdHandler);
}

CommandReceiver* CommandReceiver::GetInstance()
{
	if (instance == NULL)
	{
		instanceLock.Lock();
		if (instance == NULL)
		{
			instance = new HandlerImpl();
		}
		instanceLock.Unlock();
	}
	return instance;
}